use crate::src::struct_and_type::{size_t, UnitTestFunction};
use crate::src::test::alloc_testing::{
    alloc_test_calloc, alloc_test_free, alloc_test_get_allocated, alloc_test_malloc,
    alloc_test_realloc, alloc_test_set_limit, alloc_test_strdup,
};
use crate::src::test::framework::run_tests;

extern "C" {
    fn strcmp(_: *const i8, _: *const i8) -> i32;
}
extern "C" fn test_malloc_free() {
    let mut block: *mut () = core::ptr::null_mut();
    let mut block2: *mut () = core::ptr::null_mut();
    let mut block3: *mut () = core::ptr::null_mut();
    let mut block4: *mut () = core::ptr::null_mut();
    let mut ptr: *mut u8 = 0 as *mut u8;
    let mut i: i32 = 0;
    assert!(alloc_test_get_allocated() == 0 as u64);
    block = alloc_test_malloc(1024 as i32 as size_t);
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == 1024 as u64);
    ptr = block as *mut u8;
    i = 0;
    while i < 1024 {
        assert!((unsafe { *ptr.offset(i as isize) }) as i32 != 0);
        i += 1;
        i;
    }
    alloc_test_free(block);
    assert!(alloc_test_get_allocated() == 0 as u64);
    alloc_test_set_limit(3 as i32);
    block = alloc_test_malloc(1024 as i32 as size_t);
    assert!(!block.is_null());
    block2 = alloc_test_malloc(1024 as i32 as size_t);
    assert!(!block2.is_null());
    block3 = alloc_test_malloc(1024 as i32 as size_t);
    assert!(!block3.is_null());
    block4 = alloc_test_malloc(1024 as i32 as size_t);
    assert!(block4.is_null());
    alloc_test_free(block);
    alloc_test_free(block2);
    alloc_test_free(block3);
    alloc_test_free(block4);
}
extern "C" fn test_realloc() {
    let mut block: *mut () = core::ptr::null_mut();
    let mut block2: *mut () = core::ptr::null_mut();
    block2 = alloc_test_malloc(1024 as i32 as size_t);
    block = alloc_test_malloc(1024 as i32 as size_t);
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == (1024 as i32 + 1024) as u64);
    block = alloc_test_realloc(block, 2048 as size_t);
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == (2048 as i32 + 1024) as u64);
    block = alloc_test_realloc(block, 1500 as size_t);
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == (1500 as i32 + 1024) as u64);
    alloc_test_free(block);
    assert!(alloc_test_get_allocated() == (0 as i32 + 1024) as u64);
    block = alloc_test_realloc(0 as *mut (), 1024 as size_t);
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == (1024 as i32 + 1024) as u64);
    alloc_test_free(block);
    alloc_test_free(block2);
    assert!(alloc_test_get_allocated() == 0 as u64);
    block = alloc_test_malloc(512 as i32 as size_t);
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == 512 as u64);
    alloc_test_set_limit(1 as i32);
    block = alloc_test_realloc(block, 1024 as size_t);
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == 1024 as u64);
    assert!((alloc_test_realloc(block, 2048 as size_t)).is_null());
    assert!(alloc_test_get_allocated() == 1024 as u64);
    alloc_test_free(block);
    assert!(alloc_test_get_allocated() == 0 as u64);
    alloc_test_set_limit(1 as i32);
    block = alloc_test_realloc(0 as *mut (), 1024 as size_t);
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == 1024 as u64);
    assert!((alloc_test_realloc(0 as *mut (), 1024 as size_t)).is_null());
    assert!(alloc_test_get_allocated() == 1024 as u64);
    alloc_test_free(block);
}
extern "C" fn test_calloc() {
    let mut block: *mut u8 = 0 as *mut u8;
    let mut i: i32 = 0;
    assert!(alloc_test_get_allocated() == 0 as u64);
    block = alloc_test_calloc(16 as i32 as size_t, 64 as size_t) as *mut u8;
    assert!(alloc_test_get_allocated() == 1024 as u64);
    assert!(!block.is_null());
    i = 0;
    while i < 1024 {
        assert!((unsafe { *block.offset(i as isize) }) as i32 == 0);
        i += 1;
        i;
    }
    alloc_test_free(block as *mut ());
    assert!(alloc_test_get_allocated() == 0 as u64);
    alloc_test_set_limit(1 as i32);
    block = alloc_test_calloc(1024 as i32 as size_t, 1 as size_t) as *mut u8;
    assert!(!block.is_null());
    assert!(alloc_test_get_allocated() == 1024 as u64);
    assert!((alloc_test_calloc(1024 as i32 as size_t, 1 as size_t)).is_null());
    assert!(alloc_test_get_allocated() == 1024 as u64);
    alloc_test_free(block as *mut ());
}
extern "C" fn test_strdup() {
    let mut str: *mut i8 = 0 as *mut i8;
    assert!(alloc_test_get_allocated() == 0 as u64);
    str = alloc_test_strdup(b"hello world\0" as *const u8 as *const i8);
    assert!(!str.is_null());
    assert!((unsafe { strcmp(str, b"hello world\0" as *const u8 as *const i8) }) == 0);
    assert!(alloc_test_get_allocated() == 12 as u64);
    alloc_test_free(str as *mut ());
    assert!(alloc_test_get_allocated() == 0 as u64);
    alloc_test_set_limit(1 as i32);
    str = alloc_test_strdup(b"hello world\0" as *const u8 as *const i8);
    assert!(!str.is_null());
    assert!(alloc_test_get_allocated() == 12 as u64);
    assert!((alloc_test_strdup(b"hello world\0" as *const u8 as *const i8)).is_null());
    assert!(alloc_test_get_allocated() == 12 as u64);
    alloc_test_free(str as *mut ());
}
extern "C" fn test_limits() {
    let mut block: *mut () = core::ptr::null_mut();
    block = alloc_test_malloc(2048 as i32 as size_t);
    assert!(!block.is_null());
    alloc_test_free(block);
    alloc_test_set_limit(1 as i32);
    block = alloc_test_malloc(1024 as i32 as size_t);
    assert!(!block.is_null());
    assert!((alloc_test_malloc(1024 as i32 as size_t)).is_null());
    alloc_test_free(block);
    alloc_test_set_limit(-(1 as i32));
    block = alloc_test_malloc(1024 as i32 as size_t);
    assert!(!block.is_null());
    alloc_test_free(block);
}
static mut tests_test_alloc_testing: [UnitTestFunction; 6] = {
    [
        Some(test_malloc_free as unsafe extern "C" fn() -> ()),
        Some(test_realloc as unsafe extern "C" fn() -> ()),
        Some(test_calloc as unsafe extern "C" fn() -> ()),
        Some(test_strdup as unsafe extern "C" fn() -> ()),
        Some(test_limits as unsafe extern "C" fn() -> ()),
        None,
    ]
};
fn main_0_test_alloc_testing(mut _argc: i32, mut _argv: *mut *mut i8) -> i32 {
    run_tests(unsafe { tests_test_alloc_testing.as_mut_ptr() });
    return 0;
}
pub fn main_test_alloc_testing() {
    let mut args: Vec<*mut i8> = Vec::new();
    for arg in ::std::env::args() {
        args.push(
            (::std::ffi::CString::new(arg))
                .expect("Failed to convert argument into CString.")
                .into_raw(),
        );
    }
    args.push(::core::ptr::null_mut());
    {
        ::std::process::exit(main_0_test_alloc_testing(
            (args.len() - 1) as i32,
            args.as_mut_ptr() as *mut *mut i8,
        ) as i32)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn entry_for_test_malloc_free() {
        test_malloc_free();
    }
    #[test]
    fn entry_for_test_realloc() {
        test_realloc();
    }
    #[test]
    fn entry_for_test_calloc() {
        test_calloc();
    }
    #[test]
    fn entry_for_test_strdup() {
        test_strdup();
    }
    #[test]
    fn entry_for_test_limits() {
        test_limits();
    }
}